package com.scarecrow.olga.configuration {
	
	import com.scarecrow.olga.util.CFGReader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	
	/**
	 * This class loads and provides access to the variables in a config file.
	 * 
	 * CGF file format is basically plain text and is as follows:
		 * 
		 * //-Line and Inline comments are supported, everything in a line after a "//" will be ignored.
		 * //-spaces will always be ignored and removed for reading the file.
		 * //-line breaks are what separates statements from each other.
		 * 
		 * //variables that can be assigned primitive values
		 * VARIABLE_1 = value1;
		 * VARIABLE_2 = 15000;
		 * 
		 * //variables that can be assigned values of arrays containing primitive values
		 * VARIABLE_3 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
		 * VARIABLE_4 = [one, two, three, four, five];
	 * ...
	 * 
	 * The file extension can be any as long as the format inside is plain text, UTF-8 encoded.
	 * 
	 * @see CFGReader class for more information on file parsing.
	 * 
	 * @author Santiago.J.Elizalde
	 */
	public class CFGFile extends EventDispatcher {
		
		public static const LOAD_COMPLETED:String = "cfgLoadCompleted";
		public static const LOAD_FAILED:String = "cfgLoadFailure";
		
		//data
		private var fileName:String;
		private var content:Object;
		
		//loading
		private var req:URLRequest;
		private var loader:URLLoader;
		
		/**
		 * @param	path the path of the associated file.
		 * @param	name an identifier to mark this CFGFile instance.
		 */
		public function CFGFile(path:String, name:String = "default-config") {
			
			this.fileName = name;
			this.req = new URLRequest(path);
			this.loader = new URLLoader();
		}
		
		/**
		 * Loads a file containing configuration values. The file's url is passed to this 
		 * class through the constructor to prevent loading different files with the same
		 * instance.
		 * 
		 * The file extension can be any as long as the format inside
		 * is plain text and is UTF-8 encoded.
		 */
		public function load():void {
			this.loader.addEventListener(Event.COMPLETE, onComplete);
			this.loader.addEventListener(IOErrorEvent.IO_ERROR, onFailure);
			this.loader.dataFormat = URLLoaderDataFormat.TEXT;
			this.loader.load(req);
		}
		
		/**
		 * returns wether a value with the specified key exists in this 
		 * CFGFile instance.
		 * 
		 * @param	key the key to the queried value.
		 * @return	wether the value exists in this CFGFile instance.
		 * @throws	Error if this function is called before the file is loaded.
		 */
		public function hasValue(key:String):Boolean {
			
			if (!isLoaded) throw new Error("Cannot query a value from the CFGFile '" + fileName + "'. the configuration file is not yet loaded or loading process failed.";
			return content[key] as Boolean;
		}
		
		/**
		 * Returns a value configured in the laoded file. To see if a value exists, use the hasValue
		 * method before calling this one.
		 * 
		 * @param	key the key to the required value.
		 * @return	the value with the requested key.
		 * @throws	Error if a value with the requested key does not exist.
		 * @throws	Error if this function is called before the file is loaded.
		 */
		public function getValue(key:String):* {
			
			if (!isLoaded) throw new Error("Cannot request a value from the CFGFile '" + fileName + "'. the configuration file is not yet loaded or loading process failed.";
			var value = content[key];
			if (!value) throw new Error("The requested value with key '" + key + "' on the CFGFile '" + fileName + "' does not exist.";
			return value;
		}
		
		/**
		 * Indicates if this CFGFile's content has been loaded yet.
		 * It will only return true if the load operation was called
		 * and completed successfuly(parsing included).
		 */
		public function get isLoaded():Boolean {
			return this.content != null;
		}
		
		private function onFailure(e:IOErrorEvent):void {
			dispatchEvent(new Event(LOAD_FAILED));
		}
		
		private function onComplete(e:Event):void {
			this.content = new CFGReader().read(loader.data);
			dispatchEvent(new Event(LOAD_COMPLETED));
		}
		
	}

}